<template>
  <div class="doge-chat-panel-container">
    <img class="doge-chat-panel-close-button" :src="close" alt="close" @click="closePanel"/>
    <div class="doge-chat-history">
      <div class="doge-chat-history-item" v-for="(item, index) in chatHistory" :key="index">
        <div v-if="item.role === 'user'" class="doge-chat-history-item">
          <div class="doge-chat-history-item-user">{{ item.text }}</div>
        </div>
        <div v-else-if="item.role === 'error'" class="doge-chat-history-item">
          <div class="doge-chat-history-item-error">{{ item.text }}</div>
        </div>
        <div v-else class="doge-chat-history-item">
          <div class="doge-chat-history-item-bot" v-html="md.render(item.text)"></div>
          <div class="doge-chat-history-item-bot-loading" v-if="isRequestPending">...</div>
        </div>
      </div>
    </div>
    <div class="doge-chat-input-container">
      <textarea class="doge-chat-input-text-area" placeholder="Chat to write SQL..." rows="4" v-model="userReqForm.message"></textarea>
      <img :src="send" alt="send" class="doge-chat-input-send-button" @click="chat" :disabled="isRequestPending"/>
    </div>
  </div>
</template>

<script setup>
import close from "../assets/close.svg";
import send from "../assets/send.svg";
import MarkDownIt from "markdown-it";
import hljs from 'highlight.js';
import sql from 'highlight.js/lib/languages/sql';
import 'highlight.js/styles/ir-black.css';
import {ref, onMounted} from "vue";
import api from "../api.js";
import clipboard from 'clipboard';

import { fetchEventSource } from "@microsoft/fetch-event-source";
import {fromBase64} from "js-base64";

hljs.registerLanguage('sql', sql)

const isRequestPending = ref(false);

const props = defineProps({
  dbMetaInfo: "object",
  getEditorCode: {
    type: Function,
    required: true,
  }
})

const userReqForm = ref({
  message: "",
  userCode: "",
})

const md = new MarkDownIt({
  highlight: function (str, lang) {
    if (lang && hljs.getLanguage(lang)) {
        try {
          return '<pre class="chat-code-block" origin-code="' + str + '"">' +
              '<div class="chat-code-block-button-group"><button onclick="copyCode(this)">copy</button><button onclick="applyCode(this)">apply</button></div>' +
              '<code>' +
              hljs.highlight(lang, str, true).value +
              '</code></pre>';
        } catch (__) {}
    }
    return '<pre class="chat-code-block"><code>' + md.utils.escapeHtml(str) + '</code></pre>';
  },
  breaks: true
});

const emit = defineEmits(["closePanel", "setCode", "errorTips"]);

const chatHistory = ref([])

function closePanel() {
  emit('closePanel');
}

function copyCode(e) {
  let parentNode = e.parentNode.parentNode;
  let code = parentNode.getAttribute("origin-code");
  clipboard.writeText(code);
  alert("Code copied to clipboard")
}

function applyCode(e) {
  let parentNode = e.parentNode.parentNode;
  let code = parentNode.getAttribute("origin-code");
  emit('setCode', code);
}

onMounted(() => {
  window.copyCode = copyCode;
  window.applyCode = applyCode;
})

const ctrl = new AbortController();
const fakeChat = () => {
  let formData = JSON.parse(JSON.stringify(userReqForm.value))
  let message = formData.message.trim()
  if (message === "") {
    alert("Please enter a message to send")
    return
  }

  userReqForm.value.message = "";

  chatHistory.value.push({
    role: "user",
    text: message,
  });

  let botMessage = {
    role: "bot",
    text: "```sql\n" +
        "TESTESTSETSETSET\n" +
        "```"
  }

  chatHistory.value.push(botMessage)
}
const chat = () => {

  let message = userReqForm.value.message.trim()
  if (!(message && message !== "")) {
    emit("errorTips", "Please enter a message to send")
    return;
  }

  const dbMetaInfo = props.dbMetaInfo
  if (!dbMetaInfo) {
    emit("errorTips", "Please enter a db meta info")
    return;
  }

  if (!(dbMetaInfo.dataSource && dbMetaInfo.database && dbMetaInfo.schema
      && dbMetaInfo.dataSource !== "" && dbMetaInfo.database !== "" && dbMetaInfo.schema !== "")
  ) {
    emit("errorTips", "Database information is not provided")
    return;
  }

  const userCode = props.getEditorCode() ?? ""

  const req = {
    dataSourceName: dbMetaInfo.dataSource,
    databaseName: dbMetaInfo.database,
    schemaName: dbMetaInfo.schema,
    tableSelected: dbMetaInfo.table,
    message: message,
    userCode: userCode
  }

  userReqForm.value.message = "";
  isRequestPending.value = true;

  chatHistory.value.push({
    role: "user",
    text: message,
  });

  let botMessage = {
    role: "bot",
    text: ""
  }

  chatHistory.value.push(botMessage)


  fetchEventSource(api.chat, {
    method: 'POST',
    body: JSON.stringify(req),
    openWhenHidden: true,
    signal: ctrl.signal,
    headers: {
      "Content-Type": "application/json"
    },
    onmessage: (data) => {
      if (data.event === "token") {
        data.data = fromBase64(data.data)
        let last = chatHistory.value[chatHistory.value.length - 1]
        last.text = last.text + data.data
      }
      console.log(data);
    },
    onerror: (err) => {
      isRequestPending.value = false;
      chatHistory.value.push({role: "error", text: "发生错误，请重试"})
      throw err;
    },
    onclose: () => {
      isRequestPending.value = false;
    }
  })
}

</script>

<style scoped>

.doge-chat-panel-container {
  height: 100%;
  min-width: 300px;
  max-width: 300px;
  background-color: #ffffff;
  display: flex;
  box-shadow:-2px 2px 8px #bbb;
  border-radius: 1em;
  padding: 2em;
  margin: 40px 20px;
  display: flex;
  flex-direction: column;
}

.doge-chat-history {
  flex: 1;
  overflow-y: scroll;
}

.doge-chat-history::-webkit-scrollbar {
  display: none;
}

.doge-chat-input-container {
  border-radius: 1em;
  background-color: #f2f2f2;
  padding: 1em;
  display: flex;
}

.doge-chat-input-text-area {
  flex: 1;
  border: none;
  outline: none;
  resize: none;
  width: 100%;
  height: 100%;
  background-color: transparent;
  font-size: 1em;
}

.doge-chat-input-send-button {
  cursor: pointer;
  width: 1.8em;
  height: 1.8em;
}

.doge-chat-panel-close-button {
  display: inline-block;
  width: 1.0em;
  height: 1.0em;
  position: absolute;
  top: 10px; right: 15px;
  cursor: pointer;
}

.doge-chat-history-item {
  margin: 1em 0;
  font-size: 0.8em;
}

.doge-chat-history-item-user {
  border: 1px solid #f2f2f2;
  border-radius: 1em;
  padding: 0.5em;
  color: #888888;
  word-break: normal;
}

.doge-chat-history-item-error {
  color: #fba4a4;
  border: 1px solid #ffb6b6;
  border-radius: 1em;
  padding: 0.5em;
  word-break: normal;
  background-color: #fff1f1;
}
.doge-chat-history-item-bot {
  color: #444444;
}
</style>
<style>

.chat-code-block {
  padding: 1em;
  border: 1px solid #ddd;
  border-radius: 1em;
  overflow-x: scroll;
}

.doge-chat-history-item-bot code {
  background: rgba(255, 212, 212, 0.27);
  border: 0.5px solid #ffe6e6;
  color: #ff9090;
  border-radius: 2px;
}

.chat-code-block {
  position: relative;
}
.chat-code-block code {
  background: transparent;
  border: none;
  border-radius: 0;
  color: #888888;
}
.chat-code-block-button-group {
  position: absolute;
  top: 0.5em;
  right: 1em;
}

.chat-code-block-button-group button {
  border: none;
  background: none;
  cursor: pointer;
}

</style>